package com.tamir.template.express.parse;

import com.tamir.template.bean.TLogicNodeType;
import com.tamir.template.bean.TNode;
import com.tamir.template.config.OperatorConfig;
import com.tamir.template.config.TemplateNodeTypeConfig;
import com.tamir.template.exception.Errors;
import com.tamir.template.exception.TemplateException;
import com.tamir.template.util.StringUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author : tanggh
 * @description :〈描述〉
 * @date : 2016/10/26
 */
public abstract class AbstractLogicHandleParse implements ILogicHandleParse
{
    /**
     * 操作符开始结点正则
     */
    protected static Pattern startTagPT = Pattern.compile("(<#\\w+\\s+((\\(*(\\s*(\\(|\\))?" +
            "(-|\\+|\\*|/|>|<|=|(>=)|(<=)|(!)|(!=)|(==)|(<>)|(&&)|(\\|\\|)\\s*\\)?)?\\s*[\\w'\\" +
            ".]*\\)*)+\\)*\\s*)|(\\w+\\s+as\\s*(\\w+|(\\(\\s*\\w+\\s*,\\s*\\w+\\s*\\)))))\\s*?>)");
    /**
     * 操作符终止结点正则
     */
    protected static Pattern endTagPT = Pattern.compile("</#\\w+>");
//    protected Pattern attrPt = Pattern.compile("(\\$\\{(\\w+((\\['\\w+'\\])|(\\[\\d+\\]))?\\.)?(" +
//            "(\\w+)|(\\w+((\\['\\w+'\\])|(\\[\\d+\\])))){1}})");
    /**
     * 属性结点正则(表达式结点正则)
     */
    protected Pattern attrPt = Pattern.compile("(\\$\\{\\s*!?\\(*\\s*(\\w+((\\['\\w+'\\])|(\\[\\d+\\]))" +
            "?\\.)?((\\w+)|(\\w+" +
            "((\\['\\w+'\\])|" +
            "(\\[\\d+\\])))){1}\\s*\\)*(\\s*(\\+|-|\\*|/|=|<|>|!|>=|<=|<>|&&|\\|\\||!=)\\s*!?\\(*\\s*(\\w+(" +
            "(\\['\\w+'\\])|(\\[\\d+\\]))?\\.)?((\\w+)|(\\w+((\\['\\w+'\\])|(\\[\\d+\\]))))" +
            "{1}\\s*\\)*)*\\})");

    @Override
    public List<TNode> parse(TNode parentNode, String templateText)
    {
        Stack<TNode> nodeStacks = new Stack<TNode>();

        Matcher matcher = startTagPT.matcher(templateText);
        Matcher endTagMatcher = endTagPT.matcher(templateText);
        if(parentNode.getSubNodeList() == null){
            parentNode.setSubNodeList(new ArrayList<TNode>());
        }
        String oddText = templateText;
        int index = 0;
        int start = 0;
        int end = 0;
        int endTagStart = 0;
        int endTagEnd = 0;
        List<TNode> subNodes = null;
        TNode expressNode = null;
        boolean endMatcher = false;
        //匹配到上个tag的终止符
        boolean isEndTagOfLastTag = false;
        int minerStart = 0;
        TNode latestExpressNode = null;
        String endExpress = null;
        String nextOddText = null;
        TNode tmpParentNode = null;
        while(matcher.find()){
            tmpParentNode = nodeStacks.isEmpty() ? parentNode : nodeStacks.peek();
            subNodes = tmpParentNode.getSubNodeList();
            endMatcher = false;
            start = index + matcher.start();
            end = index + matcher.end();
            if(endTagMatcher.find()){
                endMatcher = true;
                endTagStart = index + endTagMatcher.start();
                endTagEnd = index + endTagMatcher.end();
            }
            minerStart = start - endTagStart > 0 ? endTagStart : start;
            //判断当前位置是否是上个tag的结束标签位置,如果是不需要执行text的parse
            isEndTagOfLastTag = endMatcher && (minerStart == endTagStart);
            //结点是一一对应的,如果找不到结束结点抛出异常
            if(endMatcher){
                endExpress = oddText.substring(endTagStart, endTagEnd);
                latestExpressNode = nodeStacks.empty()? null : nodeStacks.peek();
                if(latestExpressNode != null && latestExpressNode.gettLogicType().gettLogicType()
                        .equalsIgnoreCase
                        (getLogicTypeKey
                                (endExpress))){
                    throw new TemplateException(Errors.syntax_error_tag_mismatch, latestExpressNode.getExpress());
                }
            }else{
                latestExpressNode = nodeStacks.empty()? null : nodeStacks.peek();
                if(latestExpressNode != null){
                    throw new TemplateException(Errors.syntax_error_tag_mismatch, latestExpressNode.getExpress());
                }else{
                    throw new TemplateException(Errors.syntax_error_tag_mismatch, getLogicTypeKey(oddText.substring(start, end)));
                }
            }
            if(minerStart > index){
                subNodes.addAll(TemplateNodeTypeConfig.getInstance().getILogicHandleParse
                        (TemplateNodeTypeConfig.NODE_TYPE_TEXT).parse
                        (tmpParentNode,
                        oddText.substring(index,
                        minerStart)));
            }
            //index下一次匹配的起点,取开始结点和终止结点中较小的结束下标
            index = end - endTagEnd > 0 ? endTagEnd : end;

            //是不是上一个结束标签
            if(!isEndTagOfLastTag){
                expressNode = this.genTNodeExpress(tmpParentNode, oddText.substring(start, end));
                subNodes.add(expressNode);
                nodeStacks.push(expressNode);
            }else{
                if(latestExpressNode != null){
                    nodeStacks.pop();
                }
            }
            nextOddText = oddText.substring(index, oddText.length());
            matcher.reset(nextOddText);
            endTagMatcher.reset(nextOddText);
        }
        nextOddText = oddText.substring(index, oddText.length());
        endTagMatcher.reset(nextOddText);
        int lastEndTagIndex = index;
        while (endTagMatcher.find()){
            tmpParentNode = nodeStacks.isEmpty() ? parentNode : nodeStacks.peek();
            subNodes = tmpParentNode.getSubNodeList();
            endTagStart = index + endTagMatcher.start();
            endTagEnd = index + endTagMatcher.end();
            endExpress = oddText.substring(endTagStart, endTagEnd);
            if(endTagStart > lastEndTagIndex){
                subNodes.addAll(TemplateNodeTypeConfig.getInstance().getILogicHandleParse
                        (TemplateNodeTypeConfig.NODE_TYPE_TEXT).parse(tmpParentNode, oddText.substring(lastEndTagIndex,
                        endTagStart)));
            }
            latestExpressNode = nodeStacks.empty()? null : nodeStacks.peek();
            if(latestExpressNode != null && latestExpressNode.gettLogicType().gettLogicType().equalsIgnoreCase
                    (getLogicTypeKey
                            (endExpress))){
                throw new TemplateException(Errors.syntax_error_tag_mismatch, latestExpressNode.getExpress());
            }
            if(latestExpressNode != null){
                nodeStacks.pop();
            }
            lastEndTagIndex = endTagEnd;
        }
        if(oddText.length() - lastEndTagIndex > 0){
            TNode node = new TNode();
            node.settLogicType(TemplateNodeTypeConfig.getInstance().getRegisterLogicTypeByKey(TemplateNodeTypeConfig.NODE_TYPE_TEXT));
            parentNode.getSubNodeList().addAll(TemplateNodeTypeConfig.getInstance().getILogicHandleParse
                    (TemplateNodeTypeConfig.NODE_TYPE_TEXT).parse(parentNode, oddText
                    .substring(lastEndTagIndex)));
        }
        if(!nodeStacks.isEmpty()){
            throw new TemplateException(Errors.syntax_error_tag_mismatch, nodeStacks.peek().getExpress
                    ());
        }
//        parentNode.setSubNodeList(subNodes);
        return parentNode.getSubNodeList();
    }

    /**
     * 生成文本对应结点
     * @param parentNode
     * @param oddText
     * @return
     */
    private TNode genTNodeExpress(TNode parentNode, String oddText){
        TNode node = new TNode();
        node.settLogicType(getRegisteredLogicType(getLogicTypeKey
                (oddText)));
        node.setExpress(oddText);
        node.setParentNode(parentNode);
        node.setSubNodeList(new ArrayList<TNode>());
        ILogicHandleParse parse = getILogicHandleParse(node);
        parse.parseIOKeyForNode(node);
        return node;
    }

    private TLogicNodeType getRegisteredLogicType(String key){
        TLogicNodeType nodeType = TemplateNodeTypeConfig.getInstance().getRegisterLogicTypeByKey
                (key);
        if(nodeType == null){
            throw new TemplateException(Errors.express_not_registered);
        }
        return nodeType;
    }

    public String getLogicTypeKey(String express){
        String key = null;
        if(StringUtil.isNotEmpty(express)){
            String[] exArray = express.split("\\s");
            if(exArray.length > 0){
                key = exArray[0].replaceAll("<#", "").replaceAll("</#", "").replaceAll("\\s", "");
            }
        }
        if(key == null){
            throw new TemplateException(Errors.syntax_error, express);
        }
        return key;
    }
    /**
     * 获取node的值处理类
     * @param node
     * @return
     */
    public ILogicHandleParse getILogicHandleParse(TNode node)
    {
        ILogicHandleParse handle = TemplateNodeTypeConfig.getInstance().getILogicHandleParse(node
                .gettLogicType().gettLogicType());
        if (handle == null)
        {
            throw new TemplateException(Errors.logic_handle_parse_not_registered, node
                    .gettLogicType().gettLogicType());
        }
        return handle;
    }

    /**
     * 设置node的输入输出关键字和对应的值
     *
     * @param node
     */
    public void parseIOKeyForNode(TNode node)
    {
        if(node != null && node.gettLogicType().gettLogicType().equalsIgnoreCase
                (TemplateNodeTypeConfig.NODE_TYPE_LIST)){
            String keyAndValue = node.getRealExpress().replaceAll("as", "").replaceAll("\\s+", " ");
            String[] valueArray = keyAndValue.split("\\s");
            if(valueArray.length > 1){
                node.setInputKey(valueArray[1]);
                node.setOutKey(valueArray[2]);
            }
        }
    }

    /**
     * 生成属性结点
     * @param parentNode
     * @param oddText
     * @return
     */
    protected TNode genTNodeAttribute(TNode parentNode, String oddText){
        Matcher m = attrPt.matcher(oddText);
        if(!m.find()){
            throw new TemplateException(Errors.syntax_error, oddText);
        }
        TNode node = new TNode();
        String nType = TemplateNodeTypeConfig.NODE_TYPE_ATTRIBUTE;
        //如果包含表达式操作符则认为是操作符表达式需要特殊解析
        if(OperatorConfig.getInstance().isLogicOperator(oddText)){
            nType = TemplateNodeTypeConfig.NODE_TYPE_OPERATOR;
        }
        node.settLogicType(TemplateNodeTypeConfig.getInstance().getRegisterLogicTypeByKey
                (nType));
        node.setExpress(oddText);
        node.setParentNode(parentNode);

        ILogicHandleParse parse = getILogicHandleParse(node);
        parse.parseIOKeyForNode(node);
        return node;
    }
}
